Index  Decision Records ADR-186: Native Cross-Document Links (Markdown and Wiki)

ADR-186: Native Cross-Document Links (Markdown and Wiki)

1 Status

Date Status
01-06-2026 Proposed
01-06-2026 Accepted
04-06-2026 In-Progress
04-06-2026 Implemented

2 Context

Almirah has two independent linking mechanisms:

For free-text links the current behaviour is inconsistent across the document types a project actually contains:

The root causes are structural: the link-target registry holds only specification ids keyed by a hyphen-breaking stem; there is no map from a document to its generated output path and no function to compute the relative URL between any two generated pages (per-type output depth is hardcoded via instance_of? ladders); the link builder has no knowledge of which page it is currently rendering; and the parser has no [[…]] token.

Two project constraints shape the solution:

  1. A decision record's number is unique across the whole project; its folder is only a filesystem grouping convenience. A link to a decision record therefore resolves by its unique identifier, independent of which folder it lives in. (Generated decision pages are already named by id — adr-185.html — so this is the natural mapping.)
  2. Markdown cross-document links must use native relative-path semantics, so that the same link the author writes is navigable in an editor (VS Code) and by GenAI tooling that reads the Markdown directly. The link's relative path is resolved against the linking file's own directory; Almirah substitutes the corresponding generated page in the HTML output without changing the on-disk navigability of the source.

3 Decision

Introduce native cross-document linking with two complementary syntaxes, backed by a single document registry and a single relative-URL mechanism. Unresolved targets are reported as broken references.

3.1 Document registry

Build one registry covering every managed document type (specifications, test protocols, decision records, source files, the index, and the decisions overview). Each entry records the document's generated output path relative to the build root (e.g. specifications/srs/srs.html, tests/protocols/tp-001/tp-001.html, decisions/release 0.4.1/adr-185.html). The registry is keyed for lookup by:

Decision records are keyed by their unique id regardless of folder (constraint 1).

3.2 Relative-URL mechanism (unified)

Add a single helper that, given the generated output path of the page currently being rendered and the generated output path of a target document, returns the relative URL between them (using Pathname#relative_path_from), with forward-slash separators and percent-encoded spaces.

This replaces the hardcoded per-type depth handling: the instance_of?-based ../, ../../, ../../../ ladders for stylesheet, script, index, and decisions-overview links are reworked to use the same helper, so all internal links share one mechanism. To make this possible, the renderer passes the current document's output location into the link builder, which today has no such context.

3.3 Native Markdown cross-document links

A Markdown link [text](relative/path.md) whose relative path — resolved against the linking document's source directory — points at a managed document's source file is rewritten in the HTML output to a relative URL targeting that document's generated page. Because generated files are id-named, the rewrite maps the source file to the output path (e.g. source …/adr-177-overview-pie-chart.md → output …/adr-177.html); it is not a naive .md.html extension swap.

The author's source link remains a valid on-disk relative path to the target .md, so it stays navigable in an editor and by GenAI tooling (constraint 2).

3.4 Double-bracket (Obsidian / wiki) links

A [[target]] link resolves target to a managed document by its **unique id (or filename)**, independent of folder, and is rendered as a relative URL to that document's generated page. The parser gains a [[…]] token for this form.

3.5 Aliases and anchors

3.6 Unresolved links

A cross-document link (either syntax) whose target cannot be resolved to a managed document is reported as a broken reference, naming the linking document, and is rendered as a visibly broken link — consistent with how dangling >[ID] references are surfaced (SRS-023). The build still completes.

3.7 External links

Links with an explicit external scheme (http:, https:, mailto:, …) are left unchanged and continue to render as external links; they are never treated as cross-document targets.

4 Scope

Item Status Start Date Target Date Description
Requirements Done 01-06-2026 04-06-2026 New SRS items (SRS-088 onward) covering: native Markdown relative cross-document links rewritten to the target's generated page; preserved on-disk editor navigability; double-bracket [[target]] links resolved by unique id/filename independent of folder; alias [[target|text]]; anchors on both forms; the relative-URL-from-current-page mechanism for all internal links; broken-reference reporting for unresolved targets; external links left unchanged
Code Done 01-06-2026 04-06-2026 Build a project-wide document registry (id and source-path keys → output path) populated for all doc types; add a relative-URL helper (Pathname#relative_path_from, forward slashes, encoded spaces); pass the current document's output location into the text-line link builder; rewrite TextLine#link to resolve native Markdown relative links and emit correct relative HTML URLs; add a [[…]] token to the parser with alias and anchor support resolving via the registry; report unresolved targets as broken; rework the hardcoded instance_of? depth ladders in base_document to use the shared relative-URL helper; remove the backslash-separator and word-only-stem defects
Tests Done 01-06-2026 04-06-2026 End-to-end tests in spec/e2e/cross_document_links_spec.rb (12 examples): spec↔spec, spec↔protocol, decision↔decision, decision↔spec Markdown links each resolve to the correct generated page with a forward-slash relative URL; a decision link resolves by id regardless of folder; [[target]], [[target|alias]], [[target#anchor]], and path.md#anchor all resolve; an unresolved target is reported and rendered broken; an external http(s)/mailto link is left unchanged; source Markdown links remain valid relative paths on disk. Unit tests for the relative-URL helper and the document registry under spec/

5 Out of Scope

6 Consequences

6.1 Positive

6.2 Negative

6.3 Neutral

7 Alternatives Considered

8 Software Versions

Software Version Category Software Version ID
Latest Released Version 0.4.0
Issue Found in Version n/a
Target Release Version 0.4.1

9 Affected Documents

# Proposed Text Req-ID
1 The software shall resolve a Markdown link whose target, after resolving the link's relative path against the linking document's source directory, is a managed document's source file, and shall render it in the HTML output as a relative link to that target document's generated page. SRS-088
2 The software shall preserve the on-disk relative validity of a Markdown cross-document link, so that the link in the source Markdown navigates to the target Markdown file while the generated HTML link navigates to the corresponding generated page. SRS-089
3 The software shall support a double-bracket cross-document link of the form [[target]] that resolves the target to a managed document by its unique document identifier or filename, independent of the document's folder location. SRS-090
4 The software shall support an alias in a double-bracket link of the form [[target|display text]], rendering the display text as the visible link text. SRS-091
5 The software shall support an anchor fragment in a cross-document link, written as target#fragment in a Markdown link and as [[target#fragment]] in a double-bracket link, producing an HTML link to that fragment within the target document's generated page. SRS-092
6 The software shall compute the relative URL of every internal link from the location of the generated page that contains the link to the location of the target's generated page, using forward-slash separators. SRS-093
7 The software shall report a cross-document link whose target cannot be resolved to a managed document as a broken reference, naming the linking document, and shall render it as a visibly broken link without aborting the build. SRS-094
8 The software shall leave links with an external scheme (such as "http", "https", or "mailto") unchanged and shall not treat them as cross-document targets. SRS-095

10 References

11 Review Evidences